package com.thunder.ktv.scoreengine2sdk;

import android.media.AudioTrack;
import android.os.Build;
import android.util.Log;

import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

/**
 * ScoreEngine2 - 二代评分引擎Java接口
 * 封装了C++多维评分引擎的功能，提供给Android应用使用
 */
public class ScoreEngine2 {

    // Used to load the 'ts_scoreengine2sdk' library on application startup.
    static {
        System.loadLibrary("ts_scoreengine2sdk");
    }

    // 评分引擎句柄（由native代码设置,java不用这个,在native使用,不要删除）
    private long nativeEngineHandle = 0;

    public static final int SPECTRUM_SIZE = 512;
    public static final int AUDIO_FRAME_SIZE = 1024;
    public static final int SAMPLE_RATE = 48000;

    /**
     * 单帧特征类
     * 对应C++中的FrameFeature结构体
     */
    public static class FrameFeature {
        public int frameIndex;    // 帧索引
        public float vadValue;    // 当前帧VAD值（语音活动检测），范围0.0-1.0
        public float energy;      // 当前帧能量值
        public float pitch;       // 音高值
        public float brightness;  // 亮度值
        public float timbre;      // 音色值

        @Override
        public String toString() {
            return "FrameFeature{" +
                    "frameIndex=" + frameIndex +
                    ", vadValue=" + vadValue +
                    ", energy=" + energy +
                    ", pitch=" + pitch +
                    ", brightness=" + brightness +
                    ", timbre=" + timbre +
                    '}';
        }
    }

    /**
     * 评分结果类
     * 对应C++中的ScoreResult结构体
     */
    public static class ScoreResult {
        // 总体分数（0-100）
        public int scoreFlag;       // 分数更新标志
        public int overallScore;    // 总体分数
        public int pitchScore;      // 音高总分
        public int brightnessScore; // 亮度总分 0-1
        public int rhythmScore;     // 节奏总分
        public int emotionScore;    // 情感总分
        public int breathScore;     // 气息总分
        public int timbreScore;     // 音色总分
        
        public int totalFrames;     // 总帧数
        public FrameFeature frameFeature = new FrameFeature();  // 当前帧特征
        public FrameFeature baseFrameFeature = new FrameFeature();  // 基准帧特征

        public boolean isValid()
        {
            return scoreFlag == 1;
//            return scoreFlag == 1 || frameFeature.frameIndex < 2;
//            return overallScore == 0 && pitchScore == 0 && brightnessScore == 0 && rhythmScore == 0 && emotionScore == 0 && breathScore == 0 && timbreScore == 0;
        }

        @Override
        public String toString() {
            return "ScoreResult{" +
                    "scoreFlag=" + scoreFlag +
                    ", overallScore=" + overallScore +
                    ", pitchScore=" + pitchScore +
                    ", brightnessScore=" + brightnessScore +
                    ", rhythmScore=" + rhythmScore +
                    ", emotionScore=" + emotionScore +
                    ", breathScore=" + breathScore +
                    ", timbreScore=" + timbreScore +
                    ", totalFrames=" + totalFrames +
                    ", frameFeature=" + frameFeature +
                    ", baseFrameFeature=" + baseFrameFeature +
                    '}';
        }
    }

    /**
     * 评分权重类
     * 对应C++中的ScoreWeights结构体
     */
    public static class ScoreWeights {
        public float pitchWeight;      // 音高权重
        public float brightnessWeight; // 亮度权重
        public float rhythmWeight;     // 节奏权重
        public float emotionWeight;    // 情感权重
        public float breathWeight;     // 气息权重
        public float timbreWeight;     // 音色权重
    }

    /**
     * 难度因子类
     * 对应C++中的DifficultyFactors结构体
     */
    public static class DifficultyFactors {
        public float pitchTolerance;   // 音高容忍度，值越高越宽容
        public float rhythmTolerance;  // 节奏容忍度
        public float otherTolerances;  // 其他维度容忍度
    }

    /**
     * 评分引擎配置类
     * 对应C++中的ScoreEngineConfig结构体
     */
    public static class ScoreEngineConfig {
        public int enabledDimensions;    // 启用的评分维度（使用ScoreDimension.combine()方法）
        public SongStyle style;          // 歌曲风格
        public DifficultyLevel difficulty; // 难度等级
        public ScoreWeights weights;     // 自定义权重（为null则使用预设权重）
        public DifficultyFactors factors;// 自定义难度因子（为null则使用预设难度）
        
        /**
         * 创建默认配置
         * @return 默认配置对象
         */
        public static ScoreEngineConfig createDefault() {
            ScoreEngineConfig config = new ScoreEngineConfig();
            config.enabledDimensions = ScoreDimension.ALL.getValue();
            config.style = SongStyle.POP;
            config.difficulty = DifficultyLevel.NORMAL;
            return config;
        }
    }

    /**
     * CharEntry - 对应native的CharEntry结构体
     * 用于保存基准文件中的每个字的信息
     */
    public static class CharEntry {
        public int startFrame;   // 字起始帧索引
        public int endFrame;     // 字结束帧索引
        public float energy;     // 区间平均能量
        public float pitch;      // 区间音调中位数
        public String text;      // 字符串内容（UTF-8编码）

        @Override
        public String toString() {
            return "CharEntry{" +
                    "startFrame=" + startFrame +
                    ", endFrame=" + endFrame +
                    ", energy=" + energy +
                    ", pitch=" + pitch +
                    ", text='" + text + '\'' +
                    '}';
        }
    }

    // /**
    //  * 获取基准文件中的所有CharEntry信息
    //  * @return CharEntry列表
    //  */
    // public native java.util.List<CharEntry> getCharEntryList();

    /**
     * 获取当前引擎的data_offset（即CharEntry区的起始偏移）
     * @return 偏移字节数
     */
    public native int getDataOffset();

    private List<CharEntry> charEntries = new ArrayList<>();

    public List<CharEntry> getCharEntries() {
        return charEntries;
    }

    /**
     * 初始化评分引擎
     * @param baseFileData 基准文件数据
     * @param config 配置参数
     * @return 是否初始化成功
     */
    public boolean initScoreEngine(byte[] baseFileData, ScoreEngineConfig config) {
        if (baseFileData == null || baseFileData.length == 0) {
            return false;
        }

        Log.d(TAG, "initScoreEngine: " + config.difficulty);
        Log.d(TAG, "ScoreEngineVersion: v1.5");
        curFrameIndex = 0;
        // 调用native方法初始化评分引擎
        boolean ret = initScoreEngine(baseFileData, baseFileData.length, AUDIO_FRAME_SIZE, SAMPLE_RATE, config);
        if(ret){
            int offset = getDataOffset();
            charEntries = parseCharEntryList(baseFileData,offset);
//            charEntries.forEach(charEntry -> Log.d(TAG, "accept: " + charEntry));
        }
        return ret;
    }

    // Native方法声明
    private native boolean initScoreEngine(byte[] baseFileData, int dataSize, int frameSize, int sampleRate, ScoreEngineConfig config);

    /**
     * 获取初始化错误码
     * 
     * @return 成功返回0，失败返回错误代码
     */
    public static native int getInitError();
    
    /**
     * 获取初始化错误码（枚举类型）
     * 
     * @return 错误码枚举
     */
    public static ErrorCode getInitErrorCode() {
        return ErrorCode.fromValue(getInitError());
    }

    /**
     * 实时评分接口函数
     * 
     * @param audioFrame 输入音频数据 必须为1024 ，
     *                   注意这float 取值范围 为【-1 到 1】，所以如果是
     *                      16位采样，则需要将16位采样值转换为float，然后除以32768
     *                      如果是8位采样，则需要将8位采样值转换为float，然后除以128
     * @param frameIndex 当前帧索引
     * @param result 评分结果输出
     * @param spectrum 频谱数据，固定512点，前256点为参考频谱，后256点为当前帧频谱（可为null）
     * @return 成功返回0，失败返回错误代码
     */
    private native int scoreAudioFrame(float[] audioFrame, int frameIndex, ScoreResult result, float[] spectrum);

    private int curFrameIndex = 0;
    public void cleanFrameIndex() {
        curFrameIndex = 0;
        Log.d(TAG, "cleanFrameIndex: ");
    }
    public int getCurFrameIndex() {
        return curFrameIndex;
    }

    /**
     * 获取打分现在的时间节点，单位 ms
     * @return
     */
    public long getCurScorePtsMs()
    {
        return (long) ((float)curFrameIndex * AUDIO_FRAME_SIZE / (float) ScoreEngine2.SAMPLE_RATE * 1000);
    }

    /**
     * 实时评分接口函数（支持 short[] 输入，自动转换为 float[] 后调用原有接口）
     * @param audioFrame 输入音频数据（short数组，长度必须为1024）
     * @param frameIndex 当前帧索引
     * @param result 评分结果输出
     * @param spectrum 频谱数据，固定512点，前256点为参考频谱，后256点为当前帧频谱（可为null）
     * @return 成功返回0，失败返回错误代码
     */
    private static final String TAG = "ScoreEngine2";
    private static final int FRAME_FIX_STEP = 30;
    public ErrorCode scoreAudioFrame(short[] audioFrame, ScoreResult result, float[] spectrum, long videoPts) {
        if (audioFrame == null || audioFrame.length != AUDIO_FRAME_SIZE) {
            return ErrorCode.FRAME_SIZE_MISMATCH; // 参数错误
        }
        float[] floatFrame = new float[audioFrame.length];
//        Arrays.fill(floatFrame,0.1f);
        for (int i = 0; i < audioFrame.length; i++) {
            floatFrame[i] = (float) audioFrame[i]/(float)Short.MAX_VALUE;
//            if(floatFrame[i] > 0)
//            Log.d(TAG, "scoreAudioFrame: " + floatFrame[i]);
        }

        curFrameIndex++;
        if(videoPts > 0){
            long ptsDiff = Math.abs(videoPts - getCurScorePtsMs());
//        Log.d(TAG, "scoreAudioFrame: " + Arrays.toString(audioFrame));
            if(ptsDiff > FRAME_FIX_STEP){
//            Log.d(TAG, "scoreAudioFrame: " + videoPts);
//            Log.d(TAG, "scoreAudioFrame aaa: " + curFrameIndex);
                int oldCurFrameIndex = curFrameIndex;
                curFrameIndex = (int) ((videoPts) / 1000f * ScoreEngine2.SAMPLE_RATE/ AUDIO_FRAME_SIZE);
//            Log.d(TAG, "scoreAudioFrame bbb: " + curFrameIndex);
                Log.d(TAG, "scoreAudioFrame: ptsDiff " + ptsDiff + " 大于 " + FRAME_FIX_STEP + "," + " 校准打分index [" + oldCurFrameIndex + " -> " + curFrameIndex + "]");
            }
        }
        return ErrorCode.fromValue(scoreAudioFrame(floatFrame, curFrameIndex, result, spectrum));
    }

    /**
     * 释放评分引擎资源
     */
    public native void releaseScoreEngine();

    /**
     * 获取引擎版本信息
     * 
     * @return 版本信息字符串
     */
    public native String getEngineVersion();

    // 解析baseFileData中的CharEntry列表
    public static List<CharEntry> parseCharEntryList(byte[] baseFileData, int dataOffset) {
        List<CharEntry> list = new ArrayList<>();
        if (baseFileData == null || dataOffset < 0 || dataOffset >= baseFileData.length) return list;
        ByteBuffer buffer = ByteBuffer.wrap(baseFileData);
        buffer.order(ByteOrder.LITTLE_ENDIAN); // 如果C端是小端序
        buffer.position(dataOffset);
        while (buffer.remaining() >= 32) {
            int startFrame = buffer.getInt();
            int endFrame = buffer.getInt();
            float energy = buffer.getFloat();
            float pitch = buffer.getFloat();
            byte[] textBytes = new byte[16];
            buffer.get(textBytes);
            // 检查text是否全0
            boolean allZero = true;
//            for (byte b : textBytes)
//                if (b != 0) {
//                    allZero = false;
//                    break;
//                }
//            if (allZero)
//                break;
            CharEntry entry = new CharEntry();
            entry.startFrame = startFrame;
            entry.endFrame = endFrame;
            entry.energy = energy;
            entry.pitch = pitch;
            entry.text = new String(textBytes, StandardCharsets.UTF_8).trim();
            list.add(entry);
        }
        return list;
    }
}